
package com.jf.cloud.multishop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.jf.cloud.api.delivery.feign.AreaFeignClient;
import com.jf.cloud.api.delivery.vo.AreaVO;
import com.jf.cloud.api.leaf.feign.SegmentFeignClient;
import com.jf.cloud.api.multishop.bo.OrderChangeShopWalletAmountBO;
import com.jf.cloud.api.multishop.bo.ShopWalletBO;
import com.jf.cloud.api.order.constant.PurchaseOrderWaitStatus;
import com.jf.cloud.api.user.bo.RechargeNotifyBO;
import com.jf.cloud.common.cache.constant.LockCacheNames;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.constant.DistributedIdKey;
import com.jf.cloud.common.constant.SendTypeEnum;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.bo.OrderStatusBO;
import com.jf.cloud.common.order.bo.PayNotifyBO;
import com.jf.cloud.common.order.vo.OrderSimpleAmountInfoBO;
import com.jf.cloud.common.order.vo.SendNotifyBO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.util.PriceUtil;
import com.jf.cloud.multishop.bo.mongo.MongoShopWalletLogBO;
import com.jf.cloud.multishop.constant.ShopWalletAmountType;
import com.jf.cloud.multishop.constant.ShopWalletChangeReason;
import com.jf.cloud.multishop.constant.ShopWalletIoType;
import com.jf.cloud.multishop.constant.ShopWalletZoneConstant;
import com.jf.cloud.multishop.dto.ShopWalletLogSearchDTO;
import com.jf.cloud.multishop.mapper.ShopWalletMapper;
import com.jf.cloud.multishop.mapper.ShopWalletZoneMapper;
import com.jf.cloud.multishop.model.ShopWallet;
import com.jf.cloud.multishop.service.*;
import com.jf.cloud.multishop.vo.ShopWalletVO;
import com.jf.cloud.multishop.vo.ShopWalletZoneInfoVO;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 商家钱包信息
 *
 * @author zz
 * @date 2021-01-07 16:41:03
 */
@Service
public class ShopWalletServiceImpl implements ShopWalletService {

    @Autowired
    private ShopWalletMapper shopWalletMapper;
    @Autowired
    private ShopWalletLogService shopWalletLogService;
    @Autowired
    private SegmentFeignClient segmentFeignClient;
    @Autowired
    private AreaFeignClient areaFeignClient;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RocketMQTemplate updateShopRechargeSuccessTemplate;
    @Autowired
    private RocketMQTemplate addShopWalletLogTemplate;
    @Autowired
    private RocketMQTemplate shopWalletNotifyServiceTemplate;
    @Autowired
    private RocketMQTemplate refundShopNotifyServiceTemplate;
    @Autowired
    private RocketMQTemplate refundSuccessNotifySupplierTemplate;
    @Autowired
    private ShopWalletZoneService shopWalletZoneService;

    @Autowired
    private ShopDetailService shopDetailService;
    @Autowired
    private ShopWalletZoneMapper shopWalletZoneMapper;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RocketMQTemplate orderSettledSupplierTemplate;

    private static final Logger logger = LoggerFactory.getLogger(ShopWalletServiceImpl.class);

    @Override
    public void save(ShopWallet shopWallet) {
        shopWalletMapper.save(shopWallet);
    }

    @Override
    public void update(ShopWallet shopWallet) {
        shopWalletMapper.update(shopWallet);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAmountByOrder(List<OrderSimpleAmountInfoBO> orderSimpleAmountInfos, PayNotifyBO message, Map<Long, Long> settledAmountMap, Map<Long, Integer> salesMap) {

        // 进行分账，添加一个分账记录表，因为每一个订单进行分完帐后要进行退款，那么退款的时候也应该按照下单的时候的分账比例进行原路返回
        // 获取当前分账的比例
        List<OrderStatusBO> orderStatusList = new ArrayList<>();
        List<MongoShopWalletLogBO> shopWalletLogList = new ArrayList<>();
        List<OrderSimpleAmountInfoBO> orderSupplierAmountInfos = new ArrayList<>();
        List<Long> orderIds = orderSimpleAmountInfos.stream().map(OrderSimpleAmountInfoBO::getOrderId).collect(Collectors.toList());
        List<MongoShopWalletLogBO> mongoShopWalletLogList = shopWalletLogService.listByOrderIdsAndChangeReason(orderIds, ShopWalletChangeReason.PAY.value());
        List<Long> mongoOrderIds = mongoShopWalletLogList.stream().map(MongoShopWalletLogBO::getOrderId).collect(Collectors.toList());
        for (OrderSimpleAmountInfoBO orderSimpleAmountInfo : orderSimpleAmountInfos) {
            Long settlementAmount = 0L;
            // 商家之所以会从一笔订单拿到钱，是因为订单支付成功
            // 幂等
            if (mongoOrderIds.contains(orderSimpleAmountInfo.getOrderId())) {
                return;
            }
            // 1. 商家应收 = 商品价格 - 商家优惠 - 分销金额
            // 2. 商家应收 = 用户支付 + 平台补贴 - 分销金额
            Long changeAmount;
            Long supplierAmount = null;
            changeAmount = orderSimpleAmountInfo.getActualTotal() + orderSimpleAmountInfo.getPlatformAmount() - orderSimpleAmountInfo.getDistributionAmount() - orderSimpleAmountInfo.getPlatformCommission();
            if (!Objects.equals(orderSimpleAmountInfo.getSupplierId(), 0L)) {
                // 代销订单处理
                // 商家余额
                settlementAmount = settledAmountMap.get(orderSimpleAmountInfo.getShopId());
                // 如果商家收入金额小于供货价，0.直接转换为待采购订单（默认选中），1.通过商家已结算金额扣除差价
                Integer type = salesMap.get(orderSimpleAmountInfo.getShopId());
                // 供应商收入金额为 = 采购金额 + 运费 + 商家优惠运费 - 平台佣金
                supplierAmount = orderSimpleAmountInfo.getPurchaseAmount() + orderSimpleAmountInfo.getFreightAmount() + Math.abs(orderSimpleAmountInfo.getFreeFreightAmount());
                // 商家实际待结算金额 = 之前算法 - 运费 - 采购金额
                changeAmount = changeAmount - supplierAmount;
                // 如果商家收入金额小于供货价，判断处理
                // 代销设置为商家通过已结算账户金额扣除差价，且已结算金额小于于差价则变成待采购订单
                // 情况一，代销设置为商家直接转换成采购订单，且已结算金额小于差价则转换成采购订单
//                boolean checkAmount = (Objects.equals(type,0) && changeAmount < 0);
                // 情况二，代销设置为商家通过已结算账户金额扣除差价，且已结算金额小于于差价则变成待采购订单
                boolean checkAmountFlag = (Objects.equals(type, 0) && changeAmount < 0) || (Objects.equals(type, 1) && settlementAmount + changeAmount < 0);
                // 商家不同意采购，或者情况一，或者情况二，订单变成待采购
                if (!Objects.equals(message.getAgreePurchase(), 1) && checkAmountFlag) {
                    OrderStatusBO orderStatusBO = new OrderStatusBO();
                    orderStatusBO.setOrderId(orderSimpleAmountInfo.getOrderId());
                    orderStatusBO.setWaitPurchase(1);
                    orderStatusBO.setPurchaseSpreadAmount(Math.abs(changeAmount));
                    orderStatusList.add(orderStatusBO);
                    continue;
                }
                // 自动采购完成，代销设置为商家通过已结算账户金额自动扣除差价，且已结算金额足够，且改变金额小于0
                if (changeAmount < 0 && Objects.equals(type, 1) && settlementAmount + changeAmount > 0) {
                    OrderStatusBO orderStatusBO = new OrderStatusBO();
                    orderStatusBO.setOrderId(orderSimpleAmountInfo.getOrderId());
                    orderStatusBO.setWaitPurchase(PurchaseOrderWaitStatus.PURCHASED.value());
                    orderStatusBO.setPurchaseSpreadAmount(Math.abs(changeAmount));
                    orderStatusList.add(orderStatusBO);
                }
                supplierAmount = supplierAmount - orderSimpleAmountInfo.getPurchasePlatformCommission();
                // 处理下供应商的分账
                handleSupplierAmount(orderSupplierAmountInfos, orderSimpleAmountInfo, changeAmount, supplierAmount, shopWalletLogList);
                // 待结算金额处理
                changeAmount = Math.max(0L, changeAmount);
            }

            // 商家添加未结算金额
            Integer zoneNo = addUnsettledAmount(orderSimpleAmountInfo.getShopId(), changeAmount, null);
            // 平台添加未结算金额（平台佣金 - 平台优惠分摊优惠金额）
            long platformChangeAmount = orderSimpleAmountInfo.getPlatformCommission() + orderSimpleAmountInfo.getPurchasePlatformCommission() - orderSimpleAmountInfo.getPlatformAmount();
//            shopWalletMapper.addUnsettledAmount(Constant.PLATFORM_SHOP_ID, platformChangeAmount);

            // 获取商家钱包记录列表
            saveShopWalletLog(orderSimpleAmountInfo, changeAmount, platformChangeAmount, shopWalletLogList, zoneNo);
        }

        // 批量设置商家钱包记录id - 存店铺钱包记录到mongodb，因为上面保证了幂等性所以这里可以直接生成id保存到数据库
        if (CollUtil.isNotEmpty(shopWalletLogList)) {
            for (MongoShopWalletLogBO mongoShopWalletLogBO : shopWalletLogList) {
                mongoShopWalletLogBO.setWalletLogId(message.getShopWalletIds().remove(0));
            }
        }

        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(shopWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        message.setOrderStatusList(orderStatusList);
        if (CollectionUtil.isNotEmpty(orderSupplierAmountInfos)) {
            for (OrderSimpleAmountInfoBO orderSimpleAmountInfo : orderSupplierAmountInfos) {
                orderSimpleAmountInfo.setWalletLogId(message.getShopWalletIds().remove(0));
            }
            message.setOrderSimpleAmountInfos(orderSupplierAmountInfos);
        }

        // 分账总消息，包括分销分支&&订单采购&&供应商分账
        // 分销订单有自己的操作，分销订单不包含积分订单
        // 订单成功 ----> 商家分账成功 ----> 分销分账 ---> 供应商分账
        // 代销商品流程 订单成功 ----> 商家分账成功 ----> 分销分账 ---> 供应商分账 --->修改订单为待采购订单
        SendStatus shopWalletNotifyStatus = shopWalletNotifyServiceTemplate.syncSend(RocketMqConstant.SHOP_WALLET_NOTIFY_SERVICE_TOPIC, new GenericMessage<>(message)).getSendStatus();
        if (!Objects.equals(shopWalletNotifyStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    private void saveShopWalletLog(OrderSimpleAmountInfoBO orderSimpleAmountInfo, Long changeAmount, long platformChangeAmount, List<MongoShopWalletLogBO> shopWalletLogList, Integer zoneNo) {
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        shopWalletLog.setOrderId(orderSimpleAmountInfo.getOrderId());
        shopWalletLog.setZoneNo(zoneNo);
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());
        shopWalletLog.setReason(ShopWalletChangeReason.PAY.value());
        shopWalletLog.setShopId(orderSimpleAmountInfo.getShopId());
        shopWalletLog.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
        shopWalletLog.setPlatformIoType(platformChangeAmount >= 0 ? 1 : 0);

        shopWalletLog.setUserAmount(orderSimpleAmountInfo.getActualTotal());
        shopWalletLog.setPlatformCommission(orderSimpleAmountInfo.getPlatformCommission() + orderSimpleAmountInfo.getPurchasePlatformCommission());
        shopWalletLog.setPlatformChangeAmount(shopWalletLog.getUserAmount());
        shopWalletLog.setDistributionAmount(orderSimpleAmountInfo.getDistributionAmount());
        shopWalletLog.setPlatformAmount(orderSimpleAmountInfo.getPlatformAmount());

        shopWalletLog.setShopReduceAmount(orderSimpleAmountInfo.getShopAmount());
        shopWalletLog.setShopPlatformCommission(orderSimpleAmountInfo.getPlatformCommission());

        if (!Objects.equals(orderSimpleAmountInfo.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            shopWalletLog.setShopIoType(1);
            shopWalletLog.setShopChangeAmount(changeAmount);
            shopWalletLog.setShopPlatformCommission(orderSimpleAmountInfo.getPlatformCommission());
            shopWalletLog.setPlatformChangeAmount(Math.abs(platformChangeAmount));
        }
        shopWalletLogList.add(shopWalletLog);
    }

    /**
     * 供应商采购金额处理，如果商家待结算金额改变金额小于0，减少结算金额并添加日志
     *
     * @param orderSupplierAmountInfos 采购分账信息
     * @param orderSimpleAmountInfo    订单信息
     * @param changeAmount             商家待结算改变金额
     * @param supplierAmount           供应商收入金额
     */
    private void handleSupplierAmount(List<OrderSimpleAmountInfoBO> orderSupplierAmountInfos, OrderSimpleAmountInfoBO orderSimpleAmountInfo,
                                      Long changeAmount, Long supplierAmount, List<MongoShopWalletLogBO> shopWalletLogList) {
        OrderSimpleAmountInfoBO supplierAmountBO = new OrderSimpleAmountInfoBO();
        supplierAmountBO.setOrderId(orderSimpleAmountInfo.getOrderId());
        supplierAmountBO.setPurchasePlatformCommission(orderSimpleAmountInfo.getPurchasePlatformCommission());
        supplierAmountBO.setPurchaseAmount(supplierAmount);
        supplierAmountBO.setActualTotal(orderSimpleAmountInfo.getActualTotal());
        supplierAmountBO.setSupplierId(orderSimpleAmountInfo.getSupplierId());
        supplierAmountBO.setFreightAmount(orderSimpleAmountInfo.getFreightAmount());
        supplierAmountBO.setFreeFreightAmount(orderSimpleAmountInfo.getFreeFreightAmount());
        orderSupplierAmountInfos.add(supplierAmountBO);

        if (changeAmount < 0) {
            RLock lock = redissonClient.getLock(LockCacheNames.LOCK_SHOP_WALLET_ZONE_PREFIX + orderSimpleAmountInfo.getShopId());
            try {
                lock.lock();
                // 代销订单，商家减少结算金额并添加日志
                boolean isSuccess = subSettledAmount(orderSimpleAmountInfo.getShopId(), Math.abs(changeAmount));
                if (!isSuccess) {
                    throw new LuckException("店铺结算金额不足");
                }
            } finally {
                lock.unlock();
            }
            // 添加日志
            MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
            shopWalletLog.setCreateTime(new Date());
            shopWalletLog.setUpdateTime(shopWalletLog.getCreateTime());
            shopWalletLog.setOrderId(orderSimpleAmountInfo.getOrderId());
            shopWalletLog.setReason(ShopWalletChangeReason.PURCHASE_SPREAD_AMOUNT.value());
            shopWalletLog.setShopId(orderSimpleAmountInfo.getShopId());
            shopWalletLog.setShopIoType(0);
            shopWalletLog.setShopChangeAmount(changeAmount);
            shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
            shopWalletLog.setUserAmount(orderSimpleAmountInfo.getActualTotal());
            shopWalletLog.setDistributionAmount(orderSimpleAmountInfo.getDistributionAmount());
            shopWalletLog.setShopReduceAmount(orderSimpleAmountInfo.getShopAmount());
            shopWalletLog.setPlatformAmount(orderSimpleAmountInfo.getPlatformAmount());
            shopWalletLog.setShopPlatformCommission(orderSimpleAmountInfo.getPlatformCommission());
            // 添加日志
            shopWalletLogList.add(shopWalletLog);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAmountBySettledOrder(Long orderId) {

        // 商家之所以会从一笔订单拿到钱，是因为确认收货 or 订单退款时有部分不退
        long count = shopWalletLogService.countInAmountByOrderId(orderId, ShopWalletChangeReason.SETTLED.value());
        // 幂等
        if (count > 0) {
            return;
        }
        ShopWalletLogSearchDTO shopWalletLogSearchDTO = new ShopWalletLogSearchDTO();
        shopWalletLogSearchDTO.setOrderId(orderId);
        List<MongoShopWalletLogBO> shopWalletLogs = shopWalletLogService.listByParam(shopWalletLogSearchDTO);

        // 商家&平台需要结算的钱
        MongoShopWalletLogBO payLog = null;

        MongoShopWalletLogBO shopRefundLog = new MongoShopWalletLogBO();
        shopRefundLog.setUserAmount(0L);
        shopRefundLog.setDistributionAmount(0L);
        shopRefundLog.setPlatformAmount(0L);
        shopRefundLog.setShopPlatformCommission(0L);
        shopRefundLog.setPlatformCommission(0L);
        shopRefundLog.setShopChangeAmount(0L);
        shopRefundLog.setPlatformChangeAmount(0L);
        for (MongoShopWalletLogBO shopWalletLog : shopWalletLogs) {
            // 下单
            MongoShopWalletLogBO shopPayLog = polymerizationShopWalletLog(shopRefundLog, shopWalletLog);
            if (shopPayLog != null) {
                payLog = shopPayLog;
            }
        }
        // 非积分订单需要保存店铺结算记录
        if (Objects.nonNull(payLog)) {
            // 保存店铺结算记录
            saveSettledLog(payLog, shopRefundLog);
            // 通知供应商供应商结算
            SendStatus sendSupplierStatus = orderSettledSupplierTemplate.syncSend(RocketMqConstant.ORDER_SETTLED_SUPPLIER_TOPIC, new GenericMessage<>(orderId)).getSendStatus();
            if (!Objects.equals(sendSupplierStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }

    }


    /**
     * 聚合订单支付退款导致商家金额变更的记录
     *
     * @param refundWalletLog
     * @param shopWalletLog
     * @return
     */
    private MongoShopWalletLogBO polymerizationShopWalletLog(MongoShopWalletLogBO refundWalletLog, MongoShopWalletLogBO shopWalletLog) {
        if (Objects.equals(ShopWalletChangeReason.PAY.value(), shopWalletLog.getReason())) {
            return shopWalletLog;
        }
        // 退款
        else if (Objects.equals(ShopWalletChangeReason.ORDER_REFUND.value(), shopWalletLog.getReason())) {
            refundWalletLog.setUserAmount(refundWalletLog.getUserAmount() + shopWalletLog.getUserAmount());
            refundWalletLog.setDistributionAmount(refundWalletLog.getDistributionAmount() + shopWalletLog.getDistributionAmount());
            refundWalletLog.setPlatformAmount(refundWalletLog.getPlatformAmount() + shopWalletLog.getPlatformAmount());
            refundWalletLog.setShopPlatformCommission(refundWalletLog.getShopPlatformCommission() +
                    (Objects.nonNull(shopWalletLog.getShopPlatformCommission()) ? shopWalletLog.getShopPlatformCommission() : 0L));
            refundWalletLog.setPlatformCommission(refundWalletLog.getPlatformCommission() +
                    (Objects.nonNull(shopWalletLog.getPlatformCommission()) ? shopWalletLog.getPlatformCommission() : 0L));
            // 如果因为退款收入，实际上是减少了退款的钱
            Long shopChangeAmount = (Objects.isNull(shopWalletLog.getShopIoType()) ? 0L :
                    (shopWalletLog.getShopIoType() == 1) ? -shopWalletLog.getShopChangeAmount() : shopWalletLog.getShopChangeAmount());
            Long platformChangeAmount = (Objects.isNull(shopWalletLog.getPlatformIoType()) ? 0L :
                    (shopWalletLog.getPlatformIoType() == 1) ? -shopWalletLog.getPlatformChangeAmount() : shopWalletLog.getPlatformChangeAmount());
            refundWalletLog.setShopChangeAmount(refundWalletLog.getShopChangeAmount() + shopChangeAmount);
            refundWalletLog.setPlatformChangeAmount(refundWalletLog.getPlatformChangeAmount() + platformChangeAmount);
        }
        return null;
    }


    private void saveSettledLog(MongoShopWalletLogBO shopPayLog, MongoShopWalletLogBO shopRefundLog) {
        Long shopChangeAmount = shopPayLog.getShopChangeAmount();
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
        if (!response.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        shopWalletLog.setWalletLogId(response.getData());
        shopWalletLog.setOrderId(shopPayLog.getOrderId());
        shopWalletLog.setReason(ShopWalletChangeReason.SETTLED.value());
        shopWalletLog.setShopId(shopPayLog.getShopId());
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());
        int shopIoType = shopPayLog.getShopIoType();
        if (shopChangeAmount - shopRefundLog.getShopChangeAmount() < 0) {
            shopIoType = 0;
        }
        // 如果之前未结算为负收入或者当前金额小于退款金额，则已结算的收入是负收入
        if (Objects.equals(shopIoType, 0)) {
            shopChangeAmount = -shopChangeAmount - shopRefundLog.getShopChangeAmount();
        } else {
            shopChangeAmount = shopChangeAmount - shopRefundLog.getShopChangeAmount();
        }
        shopWalletLog.setShopIoType(shopIoType);
        shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        shopWalletLog.setShopChangeAmount(Math.abs(shopChangeAmount));
        shopWalletLog.setUserAmount(shopPayLog.getUserAmount() - shopRefundLog.getUserAmount());
        shopWalletLog.setDistributionAmount(shopPayLog.getDistributionAmount() - shopRefundLog.getDistributionAmount());
        shopWalletLog.setPlatformAmount(shopPayLog.getPlatformAmount() - shopRefundLog.getPlatformAmount());
        shopWalletLog.setShopPlatformCommission(shopPayLog.getShopPlatformCommission() - shopRefundLog.getShopPlatformCommission());

        // 平台日志
        Long platformChangeAmount = shopPayLog.getPlatformChangeAmount();
        Integer platformIoType = shopPayLog.getPlatformIoType();

        if (Objects.equals(platformIoType, 0)) {
            platformChangeAmount = -platformChangeAmount - shopRefundLog.getPlatformChangeAmount();
        } else {
            platformChangeAmount = platformChangeAmount - shopRefundLog.getPlatformChangeAmount();
        }

        if (platformChangeAmount < 0) {
            platformIoType = ShopWalletIoType.EXPENDITURE.value();
            platformChangeAmount = Math.abs(platformChangeAmount);
        }
        shopWalletLog.setPlatformIoType(platformIoType);
        shopWalletLog.setPlatformChangeAmount(platformChangeAmount);
        shopWalletLog.setPlatformCommission(shopPayLog.getPlatformCommission() - shopRefundLog.getPlatformCommission());


        // 商家结算，分成 1.减少待结算金额 和 2.增加结算金额以及总结算金额 两步操作，因为添加结算金额需要上锁操作，细粒化
        // 1.减少待结算金额，订单在哪个分片加的待结算金额就从哪里减掉
        boolean subUnsettledAmountSuccess = subUnsettledAmount(shopWalletLog.getShopId(), shopPayLog.getOrderId(), shopChangeAmount);
        if (!subUnsettledAmountSuccess) {
            throw new LuckException("您的待结算金额不足，无法进行结算");
        }

        // 2.增加结算金额以及总结算金额，这里可以随机加在某个分片中
        boolean addSettledAmountSuccess = addSettledAmount(shopWalletLog.getShopId(), shopChangeAmount);
        if (!addSettledAmountSuccess) {
            throw new LuckException("结算失败");
        }

        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(shopWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        // 平台结算
//        shopWalletMapper.settledAmount(Constant.PLATFORM_SHOP_ID, platformChangeAmount);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundShopAmountByRefund(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = shopWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), ShopWalletChangeReason.ORDER_REFUND.value());
        // 幂等
        if (count > 0) {
            return;
        }
        // 先来记住几个公式：
        // 1. 商家应收 = 商品价格 - 商家优惠 - 分销金额
        // 2. 商家应收 = 用户支付 + 平台补贴 - 分销金额
        // 由于 如果优惠是按照比例来划分，那么用户选择退款金额占（订单/订单项）的比例应该是商家收入减少的比例
        // 可得两个公式：
        // 商家应收 = （商品价格 - 商家优惠 - 分销金额） *（1 - 退款金额 / 实付金额）
        // 商家应收 = （用户支付 + 平台补贴 - 分销金额） *（1 - 退款金额 / 实付金额）

        // 现规定，如果发生退款，则认为分销失效有：
        // 如果订单100元，分销10元，10元的分销费用由商家出，此时商家结算时，拿到90元。
        // 当用户进行退款，退1块的时候，分销会无效，此时商家拿回给出去的10元分销费用，并将1元给到退款用户，此时商家因为退款赚9元。 shopRealRefundAmount = -9
        // 当用户进行退款，退11块的时候，分销会无效，此时商家拿回给出去的10元分销费用，并将11元给到退款用户，此时商家因为11块退款仅亏1元。shopRealRefundAmount = 1

        // 有发生退款时：
        // 商家应收 = （商品价格 - 商家优惠） *（1 - 退款金额 / 实付金额）
        // 商家应收 = （实付金额 + 平台补贴） *（1 - 退款金额 / 实付金额）

        // 商家应退 = （实付金额 + 平台补贴） *（退款金额 / 实付金额）

        // 平台佣金应退 = 实付金额 *（退款金额 / 实付金额）

        // 商家改变金额 = 原商家应收（下单时商家应收） - 现在商家应收 - 平台佣金应退
        //             = （用户支付 + 平台补贴） - 分销金额 - （实付金额 + 平台补贴） - 平台佣金 *（退款金额 / 实付金额）
        //             = （用户支付 + 平台补贴）*（退款金额 / 实付金额） - 分销金额
        //             = （用户支付 + 平台补贴 - 平台佣金） * （退款金额 / 实付金额） - 分销金额
        //             = 退款金额 + （平台补贴 - 平台佣金）* （退款金额 / 实付金额） - 分销金额
        //             = 退款金额 + 平台补贴改变量 - 平台佣金改变量 - 分销金额


        // 平台补贴改变量
        // 平台佣金改变量
        Long shopRealRefundAmount = 0L;
        List<MongoShopWalletLogBO> shopWalletLogList = new ArrayList<>();
        if (!Objects.equals(orderChangeShopWalletAmountBO.getSupplierHandleStatus(), -1)) {
            // 商家改变金额 = 退款金额 + 平台补贴改变量 - 平台佣金改变量 -分销金额 - 供应商金额改变量 - 运费
            shopRealRefundAmount = orderChangeShopWalletAmountBO.getRefundAmount() + orderChangeShopWalletAmountBO.getPlatformAllowanceAmount()
                    - orderChangeShopWalletAmountBO.getChangePlatformCommission() - orderChangeShopWalletAmountBO.getDistributionAmount()
                    - orderChangeShopWalletAmountBO.getChangePurchaseAmount() - orderChangeShopWalletAmountBO.getFreightAmount();

            // 供应商发货订单，未发货单项退款运费处理：供应商订单的运费最终是给供应商的，商家不会得到运费的钱，按目前的业务供应商发货订单的运费可以有以下两种理解
            // 情况一：用户支付运费，运费先给到商家，然后商家将运费给供应商。按业务是这个流程，因为用户是跟商家购买的商品，商家再到供应商去请求发货
            // 情况二：平台会员包邮，用户需要支付的运费由平台出了，所以平台需要补贴运费给商家，商家再把平台补贴的运费给供应商
            // 因为供应商发货订单的运费，最终都是给到供应商，商家只是做一个中转，所以在退款的时候，商家不需要去扣除运费的金额
            // 但情况二的平台补贴金额中包含了供应商商品运费，因此在商家的计算要扣除运费的金额，避免商家又扣了一次运费造成亏损
            if (Objects.nonNull(orderChangeShopWalletAmountBO.getSupplierFreightAmount()) && !Objects.equals(orderChangeShopWalletAmountBO.getShopId(), 0L)) {
                shopRealRefundAmount = shopRealRefundAmount - orderChangeShopWalletAmountBO.getSupplierFreightAmount();
            }
        } else {

            // 商家自行处理，商家需要负担供应商应退金额
            // 商家改变金额 = 退款金额 + 平台补贴改变量 - 平台佣金改变量 -分销金额 - 供应商金额改变量 - 运费 - 平台包邮
            // 如果运费为0，但是平台免运费金额大于0，则还需要计算这个运费
            long platformFreeFreightAmount = 0L;
            if(orderChangeShopWalletAmountBO.getFreightAmount() == 0L && orderChangeShopWalletAmountBO.getPlatformFreeFreightAmount() > 0){
                platformFreeFreightAmount = orderChangeShopWalletAmountBO.getPlatformFreeFreightAmount();
            }
            // 1 + 1 - 1 - 1
            shopRealRefundAmount = orderChangeShopWalletAmountBO.getRefundAmount() + orderChangeShopWalletAmountBO.getPlatformAllowanceAmount()
                    - orderChangeShopWalletAmountBO.getChangePlatformCommission() - orderChangeShopWalletAmountBO.getDistributionAmount()
                    - orderChangeShopWalletAmountBO.getChangePurchaseAmount() - orderChangeShopWalletAmountBO.getFreightAmount() - platformFreeFreightAmount;
            // 供应商改变金额 = 供应商改变金额 + 运费 - 平台供应商佣金改变量 + 平台包邮运费
            long supplierRealRefundAmount = orderChangeShopWalletAmountBO.getChangePurchaseAmount()  + orderChangeShopWalletAmountBO.getFreightAmount()
                    - orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission() + platformFreeFreightAmount;
            // 商家自行处理供应商订单，减少商家结算金额
            if(supplierRealRefundAmount > 0){
                subSettlementAmount(supplierRealRefundAmount,orderChangeShopWalletAmountBO, shopWalletLogList,true);
            }

        }

        // 添加平台钱包记录
        saveRefundShopWalletLog(orderChangeShopWalletAmountBO, shopRealRefundAmount, shopWalletLogList);
        for (MongoShopWalletLogBO mongoShopWalletLogBO : shopWalletLogList) {
            mongoShopWalletLogBO.setWalletLogId(orderChangeShopWalletAmountBO.getWalletLogIds().remove(0));
        }
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(shopWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 通知分销，退回分销佣金
        // 通知供应商，退回供应商未结算金额
        SendStatus sendStatus = refundShopNotifyServiceTemplate.syncSend(RocketMqConstant.REFUND_SHOP_NOTIFY_SERVICE_TOPIC, new GenericMessage<>(orderChangeShopWalletAmountBO)).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    private void saveRefundShopWalletLog(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO, Long shopRealRefundAmount, List<MongoShopWalletLogBO> shopWalletLogList) {
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        handleShopLogInfo(orderChangeShopWalletAmountBO, shopRealRefundAmount, shopWalletLog);
        // 1. 订单未确认收货则扣未结算金额
        // 2. 商家撤销拼团活动时失效拼团时，将待成团的队伍进行退款

        // 此时会有两种情况，1.商家采购订单后退款 2.普通退款
        // 商家采购订单后退款，此时钱退回结算金额，为0不需要减少
        if (shopRealRefundAmount != 0L) {
            if (Objects.equals(orderChangeShopWalletAmountBO.getWaitPurchase(), PurchaseOrderWaitStatus.PURCHASED.value())) {
                // 修改结算金额
                RLock lock = redissonClient.getLock(LockCacheNames.LOCK_SHOP_WALLET_ZONE_PREFIX + orderChangeShopWalletAmountBO.getShopId());
                try {
                    lock.lock();
                    boolean isSuccess = subSettledAmount(orderChangeShopWalletAmountBO.getShopId(), shopRealRefundAmount);
                    if (!isSuccess) {
                        throw new LuckException("您的结算金额不足，无法进行退款");
                    }
                } finally {
                    lock.unlock();
                }
                shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
            } else {
                // 减少未结算金额
                boolean isSuccess = subUnsettledAmount(orderChangeShopWalletAmountBO.getShopId(), orderChangeShopWalletAmountBO.getOrderId(), shopRealRefundAmount);
                if (!isSuccess) {
                    throw new LuckException("您的待结算金额不足，无法进行退款");
                }
                shopWalletLog.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
            }
        }
        // 添加平台日志,平台日志需要加上供应商的那份佣金
        shopWalletLog.setPlatformCommission(orderChangeShopWalletAmountBO.getChangePlatformCommission() + orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission());
        // 平台实际上改变金额
        // 订单退款，补贴肯定是减少了，但是对于平台来说是赚钱了
        // 订单退款了，平台的佣金也是减少了，所以对于平台来说是亏钱的
        long platformRealRefundAmount = shopWalletLog.getPlatformAmount() - shopWalletLog.getPlatformCommission();
        shopWalletLog.setPlatformIoType(platformRealRefundAmount >= 0 ? 1 : 0);
        shopWalletLog.setPlatformChangeAmount(Math.abs(platformRealRefundAmount));
        // 添加日志
        shopWalletLogList.add(shopWalletLog);

        // 采购完成、且商家减免了金额（支付了扣除订单采购价差、或者别的优惠）
        // 如果满足上面的条件，那么shopwalletLog是店铺余额的记录，这里还需要添加一条待结算金额的记录
        if (Objects.equals(orderChangeShopWalletAmountBO.getWaitPurchase(), PurchaseOrderWaitStatus.PURCHASED.value())) {
            MongoShopWalletLogBO mongoShopWalletLogBO = new MongoShopWalletLogBO();
            BeanUtils.copyProperties(shopWalletLog, mongoShopWalletLogBO);
            mongoShopWalletLogBO.setShopChangeAmount(0L);
            mongoShopWalletLogBO.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());

            shopWalletLogList.add(mongoShopWalletLogBO);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundShopAmountByRefundAndWaitPur(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = shopWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), ShopWalletChangeReason.ORDER_REFUND.value());
        // 幂等
        if (count > 0) {
            return;
        }
        // 先来记住几个公式：
        // 1. 商家应收 = 商品价格 - 商家优惠 - 分销金额
        // 2. 商家应收 = 用户支付 + 平台补贴 - 分销金额
        // 由于 如果优惠是按照比例来划分，那么用户选择退款金额占（订单/订单项）的比例应该是商家收入减少的比例
        // 可得两个公式：
        // 商家应收 = （商品价格 - 商家优惠 - 分销金额） *（1 - 退款金额 / 实付金额）
        // 商家应收 = （用户支付 + 平台补贴 - 分销金额） *（1 - 退款金额 / 实付金额）

        // 现规定，如果发生退款，则认为分销失效有：
        // 如果订单100元，分销10元，10元的分销费用由商家出，此时商家结算时，拿到90元。
        // 当用户进行退款，退1块的时候，分销会无效，此时商家拿回给出去的10元分销费用，并将1元给到退款用户，此时商家因为退款赚9元。 shopRealRefundAmount = -9
        // 当用户进行退款，退11块的时候，分销会无效，此时商家拿回给出去的10元分销费用，并将11元给到退款用户，此时商家因为11块退款仅亏1元。shopRealRefundAmount = 1

        // 有发生退款时：
        // 商家应收 = （商品价格 - 商家优惠） *（1 - 退款金额 / 实付金额）
        // 商家应收 = （实付金额 + 平台补贴） *（1 - 退款金额 / 实付金额）

        // 商家应退 = （实付金额 + 平台补贴） *（退款金额 / 实付金额）

        // 平台佣金应退 = 实付金额 *（退款金额 / 实付金额）

        // 商家改变金额 = 原商家应收（下单时商家应收） - 现在商家应收 - 平台佣金应退
        //             = （用户支付 + 平台补贴） - 分销金额 - （实付金额 + 平台补贴） - 平台佣金 *（退款金额 / 实付金额）
        //             = （用户支付 + 平台补贴）*（退款金额 / 实付金额） - 分销金额
        //             = （用户支付 + 平台补贴 - 平台佣金） * （退款金额 / 实付金额） - 分销金额
        //             = 退款金额 + （平台补贴 - 平台佣金）* （退款金额 / 实付金额） - 分销金额
        //             = 退款金额 + 平台补贴改变量 - 平台佣金改变量 - 分销金额

        // 待采购订单肯定是待发货的，此时运费肯定要退给用户
        // 商家改变金额 = 退款金额 + 平台补贴改变量 - 平台佣金改变量 -分销金额 - 供应商金额改变量
        Long shopRealRefundAmount = orderChangeShopWalletAmountBO.getRefundAmount() + orderChangeShopWalletAmountBO.getPlatformAllowanceAmount()
                - orderChangeShopWalletAmountBO.getChangePlatformCommission() - orderChangeShopWalletAmountBO.getDistributionAmount();

        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        handleShopLogInfo(orderChangeShopWalletAmountBO, shopRealRefundAmount, shopWalletLog);
        // 1. 订单未确认收货则扣未结算金额
        // 2. 商家撤销拼团活动时失效拼团时，将待成团的队伍进行退款

        // 减少未结算金额
        boolean isSuccess = subUnsettledAmount(orderChangeShopWalletAmountBO.getShopId(), orderChangeShopWalletAmountBO.getOrderId(), shopRealRefundAmount);
        if (!isSuccess) {
            throw new LuckException("您的待结算金额不足，无法进行退款");
        }
        // 添加平台日志
        shopWalletLog.setPlatformCommission(orderChangeShopWalletAmountBO.getChangePlatformCommission());
        // 平台实际上改变金额
        // 订单退款，补贴肯定是减少了，但是对于平台来说是赚钱了
        // 订单退款了，平台的佣金也是减少了，所以对于平台来说是亏钱的
        long platformRealRefundAmount = shopWalletLog.getPlatformAmount() - shopWalletLog.getPlatformCommission();

        shopWalletLog.setPlatformIoType(platformRealRefundAmount >= 0 ? 1 : 0);
        shopWalletLog.setPlatformChangeAmount(Math.abs(platformRealRefundAmount));
        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(shopWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 通知分销，退回分销佣金
        orderChangeShopWalletAmountBO.setSupplierHandleStatus(null);
        SendStatus sendStatus = refundShopNotifyServiceTemplate.syncSend(RocketMqConstant.REFUND_SHOP_NOTIFY_SERVICE_TOPIC, new GenericMessage<>(orderChangeShopWalletAmountBO)).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    private void handleShopLogInfo(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO, Long shopRealRefundAmount, MongoShopWalletLogBO shopWalletLog) {
        shopWalletLog.setRefundId(orderChangeShopWalletAmountBO.getRefundId());
        shopWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        shopWalletLog.setReason(ShopWalletChangeReason.ORDER_REFUND.value());
        shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());

        // 用户申请的退款金额
        shopWalletLog.setUserAmount(orderChangeShopWalletAmountBO.getRefundAmount());
        // 回退的分销金额
        shopWalletLog.setDistributionAmount(orderChangeShopWalletAmountBO.getDistributionAmount());
        // 回退的平台补贴
        shopWalletLog.setPlatformAmount(orderChangeShopWalletAmountBO.getPlatformAllowanceAmount());
        shopWalletLog.setShopReduceAmount(orderChangeShopWalletAmountBO.getShopAllowanceAmount());
        // 回退的平台佣金
        shopWalletLog.setShopPlatformCommission(orderChangeShopWalletAmountBO.getChangePlatformCommission());
        // 商家改变金额
        if (shopRealRefundAmount >= 0) {
            // 扣除
            shopWalletLog.setShopIoType(0);
            shopWalletLog.setShopChangeAmount(shopRealRefundAmount);
        } else {
            // 如果算出的商品改变金额为负数，负支出等于收入，就是说要把退款记录的收支类型改为收入
            shopWalletLog.setShopIoType(1);
            shopWalletLog.setShopChangeAmount(Math.abs(shopRealRefundAmount));
        }
        shopWalletLog.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
    }

    /**
     * 商家自行处理供应商订单，减少商家结算金额
     *
     * @param orderChangeShopWalletAmountBO 退款信息
     */

    public void subSettlementAmount(Long supplierRealRefundAmount,OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO,List<MongoShopWalletLogBO> shopWalletLogList,Boolean isNowSave) {

        // 代销订单，商家减少结算金额并添加日志
        RLock lock = redissonClient.getLock(LockCacheNames.LOCK_SHOP_WALLET_ZONE_PREFIX + orderChangeShopWalletAmountBO.getShopId());
        try {
            lock.lock();
            // 代销订单，商家减少结算金额并添加日志
            boolean isSuccess = subSettledAmount(orderChangeShopWalletAmountBO.getShopId(), Math.abs(supplierRealRefundAmount));
            if (!isSuccess) {
                throw new LuckException("您的结算金额不足，无法进行退款");
            }
        } finally {
            lock.unlock();
        }

        // 添加日志
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        shopWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        shopWalletLog.setRefundId(orderChangeShopWalletAmountBO.getRefundId());
        shopWalletLog.setZoneNo(null);
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());
        shopWalletLog.setReason(ShopWalletChangeReason.REFUND_SPREAD_AMOUNT.value());
        shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
        shopWalletLog.setShopIoType(0);
        shopWalletLog.setShopChangeAmount(supplierRealRefundAmount);
        shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        shopWalletLog.setUserAmount(orderChangeShopWalletAmountBO.getRefundAmount());
        shopWalletLog.setDistributionAmount(0L);
        shopWalletLog.setShopReduceAmount(0L);
        shopWalletLog.setPlatformAmount(0L);
        shopWalletLog.setShopPlatformCommission(0L);
        // 此处用不等于null，但是可以数组为空
        if(isNowSave) {
            // 添加日志
            shopWalletLogList.add(shopWalletLog);
        }else{
            ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
            if (!response.isSuccess()) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
            shopWalletLog.setWalletLogId(response.getData());
            // 用mq批量保存钱包日志
            List<MongoShopWalletLogBO> shopWalletLogs = new ArrayList<>();
            shopWalletLogs.add(shopWalletLog);
            SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(shopWalletLogs)).getSendStatus();
            if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementShopAmountByRefund(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = shopWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), ShopWalletChangeReason.SETTLED.value());
        Long distributionAmount = Objects.isNull(orderChangeShopWalletAmountBO.getDistributionAmount()) ? 0L : orderChangeShopWalletAmountBO.getDistributionAmount();
        // 幂等
        if (count > 0) {
            return;
        }
        //    当前需要结算金额 = 用户实付金额 - 退款金额
        //    平台补贴改变量 = 平台补贴 * 当前需要结算金额 / 商品实际金额
        //    平台佣金改变量 = 平台佣金 * 当前需要结算金额 / 商品实际金额
        //    商家结算金额 =  当前需要结算金额 + 平台补贴改变量 - 平台佣金改变量
        //    平台结算金额 = 平台佣金改变量 - 平台补贴改变量
        Long settlementAmount = orderChangeShopWalletAmountBO.getActualTotal() - orderChangeShopWalletAmountBO.getRefundAmount();
        // 平台补贴改变量 （退款成功的时候已经处理了平台补贴金额，这里不需要再去计算, 但部分退款成功时，还有平台补贴金额需要结算）
        Long changePlatformAmount = orderChangeShopWalletAmountBO.getPlatformAllowanceAmount();
        // 平台佣金改变量
        Long changePlatformCommission = orderChangeShopWalletAmountBO.getPlatformCommission() - orderChangeShopWalletAmountBO.getChangePlatformCommission();
        // 商家改变金额
        Long shopSettlementAmount = settlementAmount + changePlatformAmount - changePlatformCommission;
        if (!Objects.equals(orderChangeShopWalletAmountBO.getSupplierId(), 0L)) {
            // 如果有供应商，则商家还需减去供应商收入，供应商收入 = 供应商金额 - 已退金额
//            Long supplierAmount = orderChangeShopWalletAmountBO.getChangePurchaseAmount() + orderChangeShopWalletAmountBO.getFreightAmount();
            Long supplierAmount = orderChangeShopWalletAmountBO.getRefundPurchaseAmount();
            shopSettlementAmount = shopSettlementAmount - supplierAmount;
        }
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
        if (!response.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        shopWalletLog.setWalletLogId(response.getData());
        shopWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        shopWalletLog.setReason(ShopWalletChangeReason.SETTLED.value());
        shopWalletLog.setShopId(Constant.PLATFORM_SHOP_ID);
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());

        // 结算的金额
        shopWalletLog.setUserAmount(settlementAmount);
        // 回退的分销金额
        shopWalletLog.setDistributionAmount(distributionAmount);
        // 回退的平台补贴
        shopWalletLog.setPlatformAmount(changePlatformAmount);
        shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());

        // 有可能到负数，如果为负数就不能结算店铺了
        if (shopSettlementAmount > 0L) {
            shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
            // 回退的平台佣金
            shopWalletLog.setShopPlatformCommission(changePlatformCommission);
            // 商家改变金额
            shopWalletLog.setShopChangeAmount(shopSettlementAmount);
            // 增加
            shopWalletLog.setShopIoType(1);

            // 1. 订单部分退款导致订单关闭 商家结算操作
            // 商家结算操作同订单结算一样，分成两步
            //      1.减少待结算金额，订单在哪个分片加的待结算金额就从哪里减掉
            boolean subUnsettledAmountSuccess = subUnsettledAmount(shopWalletLog.getShopId(), orderChangeShopWalletAmountBO.getOrderId(), shopSettlementAmount);
            if (!subUnsettledAmountSuccess) {
                throw new LuckException("您的待结算金额不足，无法进行退款");
            }

            //      2.增加结算金额以及总结算金额，这里可以随机加在某个分片中
            boolean addSettledAmountSuccess = addSettledAmount(shopWalletLog.getShopId(), shopSettlementAmount);
            if (!addSettledAmountSuccess) {
                throw new LuckException("店铺结算失败，无法进行退款");
            }
        }
        // 添加平台日志
        // 回退的平台佣金,还需加上供应商佣金改变量
        shopWalletLog.setPlatformCommission(changePlatformCommission + orderChangeShopWalletAmountBO.getRefundPurchasePlatformCommission());
        // 平台结算金额实际上改变金额 = 平台佣金改变量 - 平台补贴改变量
        long platformChangeAmount = shopWalletLog.getPlatformCommission() - shopWalletLog.getPlatformAmount();
        shopWalletLog.setPlatformIoType(platformChangeAmount >= 0 ? 1 : 0);
        shopWalletLog.setPlatformChangeAmount(Math.abs(platformChangeAmount));
        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(shopWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 平台添加改变结算金额
//        shopWalletMapper.settledAmount(Constant.PLATFORM_SHOP_ID, platformChangeAmount);

        // 供应商 添加结算金额
        SendStatus sendSupplierStatus = refundSuccessNotifySupplierTemplate.syncSend(RocketMqConstant.ORDER_REFUND_SUCCESS_SETTLEMENT_SUPPLIER_TOPIC, new GenericMessage<>(orderChangeShopWalletAmountBO)).getSendStatus();
        if (!Objects.equals(sendSupplierStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementShopAmountByPreSaleFail(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = shopWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getOrderId(), ShopWalletChangeReason.PRE_SALE_FAIL.value());
        // 幂等
        if (count > 0) {
            return;
        }
        //    当前需要结算金额 = 用户实付金额 - 退款金额
        //    平台补贴改变量 = 平台补贴 * 当前需要结算金额 / 商品实际金额
        //    平台佣金改变量 = 平台佣金 * 当前需要结算金额 / 商品实际金额
        //    商家结算金额 =  当前需要结算金额 + 平台补贴改变量 - 平台佣金改变量
        //    平台结算金额 = 平台佣金改变量 - 平台补贴改变量
        // 商家改变金额
        Long settlementAmount = orderChangeShopWalletAmountBO.getActualTotal();
        Long changeAmount = orderChangeShopWalletAmountBO.getActualTotal() - orderChangeShopWalletAmountBO.getPlatformCommission();
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();

        ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
        if (!response.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        shopWalletLog.setWalletLogId(response.getData());
        shopWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        shopWalletLog.setReason(ShopWalletChangeReason.PRE_SALE_FAIL.value());
        shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());

        // 结算的金额
        shopWalletLog.setUserAmount(settlementAmount);
        // 回退的分销金额
        shopWalletLog.setDistributionAmount(0L);
        // 回退的平台补贴
        shopWalletLog.setPlatformAmount(0L);
        // 回退的平台佣金
        shopWalletLog.setShopPlatformCommission(orderChangeShopWalletAmountBO.getPlatformCommission());
        // 商家改变金额
        shopWalletLog.setShopChangeAmount(changeAmount);
        // 增加
        shopWalletLog.setShopIoType(1);
        shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        // 添加店铺日志(尾款超时支付取消的订单 定金结算给商家)
        shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
        // 平台佣金
        shopWalletLog.setPlatformCommission(orderChangeShopWalletAmountBO.getPlatformCommission());
        // 平台结算金额实际上改变金额 = 平台佣金改变量
        long platformChangeAmount = shopWalletLog.getPlatformCommission();
        shopWalletLog.setPlatformIoType(platformChangeAmount >= 0 ? 1 : 0);
        shopWalletLog.setPlatformChangeAmount(Math.abs(platformChangeAmount));

        // 1. 订单超时未支付尾款 商家结算操作
        boolean isSuccess = addSettledAmount(orderChangeShopWalletAmountBO.getShopId(), changeAmount);
        if (!isSuccess) {
            throw new LuckException("结算失败，无法进行退款");
        }

        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(shopWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementShopAmountByRefundAndWaitPur(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = shopWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), ShopWalletChangeReason.SETTLED.value());
        Long distributionAmount = Objects.isNull(orderChangeShopWalletAmountBO.getDistributionAmount()) ? 0L : orderChangeShopWalletAmountBO.getDistributionAmount();
        // 幂等
        if (count > 0) {
            return;
        }
        //    当前需要结算金额 = 用户实付金额 - 退款金额
        //    平台补贴改变量 = 平台补贴 * 当前需要结算金额 / 商品实际金额
        //    平台佣金改变量 = 平台佣金 * 当前需要结算金额 / 商品实际金额
        //    商家结算金额 =  当前需要结算金额 + 平台补贴改变量 - 平台佣金改变量
        //    平台结算金额 = 平台佣金改变量 - 平台补贴改变量
        Long settlementAmount = orderChangeShopWalletAmountBO.getActualTotal() - orderChangeShopWalletAmountBO.getRefundAmount();
        // 平台补贴改变量
        Long changePlatformAmount = orderChangeShopWalletAmountBO.getPlatformAllowanceAmount();
        // 平台佣金改变量
        Long changePlatformCommission = orderChangeShopWalletAmountBO.getPlatformCommission() - orderChangeShopWalletAmountBO.getChangePlatformCommission();
        // 商家改变金额
        Long shopSettlementAmount = settlementAmount + changePlatformAmount - changePlatformCommission;

        // 4.6日待采购是订单还没结算到供应商，所以此处应该是商家纯赚的，运费不需要在结算给供应商
//        // 供应商发货订单，待采购的单项退款，如果有会员包邮，平台补贴金额中就会包含运费补贴的金额--supplierFreightAmount赋值位置：com.jf.cloud.order.service.impl.OrderRefundServiceImpl.handlePartialRefund
//        // 但待采购的订单是还未处理待结算金额的，也就是说平台补贴的运费，实际上是未从平台待结算金额扣除的
//        // 所以运费补贴的金额在退款时要从平台补贴金额中扣除，避免平台未发放运费补贴金额，退款时又给平台添加了运费补贴的金额
//        // 但不能在平台补贴改变量中扣除，否则结算记录中平台补贴改变量就会少了运费补贴的金额，因此要在改变金额中扣除
//        if (Objects.nonNull(orderChangeShopWalletAmountBO.getSupplierFreightAmount())) {
//            shopSettlementAmount = shopSettlementAmount - orderChangeShopWalletAmountBO.getSupplierFreightAmount();
//        }

        // 有可能到负数，如果为负数就不能结算了
        if (shopSettlementAmount < 0L) {
            return;
        }
        MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
        ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
        if (!response.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        shopWalletLog.setWalletLogId(response.getData());
        shopWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        shopWalletLog.setReason(ShopWalletChangeReason.SETTLED.value());
        shopWalletLog.setShopId(orderChangeShopWalletAmountBO.getShopId());
        shopWalletLog.setCreateTime(new Date());
        shopWalletLog.setUpdateTime(new Date());

        // 结算的金额
        shopWalletLog.setUserAmount(settlementAmount);
        // 回退的分销金额
        shopWalletLog.setDistributionAmount(distributionAmount);
        // 回退的平台补贴
        shopWalletLog.setPlatformAmount(changePlatformAmount);
        // 回退的平台佣金
        shopWalletLog.setShopPlatformCommission(changePlatformCommission);
        // 商家改变金额
        shopWalletLog.setShopChangeAmount(shopSettlementAmount);
        // 增加
        shopWalletLog.setShopIoType(1);

        // 1. 订单部分退款导致订单关闭 商家结算操作,此时不需要减少待结算金额
        if (shopSettlementAmount != 0L) {
            boolean isSuccess = addSettledAmount(orderChangeShopWalletAmountBO.getShopId(), shopSettlementAmount);
            if (!isSuccess) {
                throw new LuckException("结算失败，无法进行退款");
            }
        }
        shopWalletLog.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        // 添加平台日志
        // 回退的平台佣金,还需加上供应商佣金改变量
        shopWalletLog.setPlatformCommission(changePlatformCommission);
        // 平台结算金额实际上改变金额 = 平台佣金改变量 - 平台补贴改变量
        long platformChangeAmount = shopWalletLog.getPlatformCommission() - shopWalletLog.getPlatformAmount();
        shopWalletLog.setPlatformIoType(platformChangeAmount >= 0 ? 1 : 0);
        shopWalletLog.setPlatformChangeAmount(Math.abs(platformChangeAmount));

        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(shopWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 平台添加改变结算金额
//        shopWalletMapper.settledAmount(Constant.PLATFORM_SHOP_ID, platformChangeAmount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateByDistributionAmount(List<ShopWalletBO> message) {
        if (CollUtil.isEmpty(message)) {
            return;
        }
        List<MongoShopWalletLogBO> shopWalletLogList = new ArrayList<>();
        for (ShopWalletBO shopWalletBO : message) {
            Long shopId = shopWalletBO.getShopId();
            Long orderId = shopWalletBO.getOrderId();
            // 商家待结算改变金额，从分销过来的待结算金额是个负数，用来减少待结算金额
            Long unsettledAmount = shopWalletBO.getUnsettledAmount();
            // 幂等处理
            long count = shopWalletLogService.countInAmountByOrderId(orderId, ShopWalletChangeReason.DISTRIBUTION_AMOUNT.value());
            if (count > 0) {
                continue;
            }
            // 修改支付成功结算的店铺钱包日志
            ShopWalletLogSearchDTO shopWalletLogQuery = new ShopWalletLogSearchDTO();
            shopWalletLogQuery.setOrderId(orderId);
            shopWalletLogQuery.setReason(ShopWalletChangeReason.PAY.value());
            shopWalletLogQuery.setShopId(shopId);
            shopWalletLogQuery.setShopIoType(1);
            shopWalletLogQuery.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
            // 必须保存店铺分账完成，有该条分账记录后，才可以分销
            List<MongoShopWalletLogBO> shopWalletLogBOList = shopWalletLogService.listByParam(shopWalletLogQuery);
            if (CollUtil.isEmpty(shopWalletLogBOList) || Objects.isNull(shopWalletLogBOList.get(0))) {
                throw new LuckException("未找到支付成功结算的店铺钱包日志");
            }
            MongoShopWalletLogBO shopWalletLogUpdate = shopWalletLogBOList.get(0);
            shopWalletLogUpdate.setDistributionAmount(Math.abs(unsettledAmount));
            // 修改钱包日志分销金额
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(shopWalletLogUpdate.getWalletLogId()));
            Update update = new Update();
            update.set("distributionAmount", shopWalletLogUpdate.getDistributionAmount());
            update.set("updateTime", new Date());
            mongoTemplate.updateFirst(query, update, MongoShopWalletLogBO.class);

            // 更新钱包未结算金额
            addUnsettledAmount(shopId, unsettledAmount, shopWalletLogUpdate.getZoneNo());

            // 分销减少店铺钱包日志，只是为了添加一条日志，保证幂等
            MongoShopWalletLogBO shopWalletLog = new MongoShopWalletLogBO();
            ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_SHOP_WALLET_LOG);
            if (!response.isSuccess()) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
            shopWalletLog.setWalletLogId(response.getData());
            shopWalletLog.setShopId(shopId);
            shopWalletLog.setOrderId(orderId);
            shopWalletLog.setCreateTime(new Date());
            shopWalletLog.setUpdateTime(new Date());
            shopWalletLog.setShopIoType(unsettledAmount >= 0 ? 1 : 0);
            shopWalletLog.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
            shopWalletLog.setReason(ShopWalletChangeReason.DISTRIBUTION_AMOUNT.value());
            shopWalletLog.setDistributionAmount(Math.abs(unsettledAmount));
            shopWalletLog.setShopChangeAmount(Math.abs(unsettledAmount));
            shopWalletLog.setUserAmount(shopWalletLogUpdate.getUserAmount());
            shopWalletLogList.add(shopWalletLog);
        }
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addShopWalletLogTemplate.syncSend(RocketMqConstant.ADD_SHOP_WALLET_LOG_TOPIC, new GenericMessage<>(shopWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public List<ShopWalletVO> listByShopIds(List<Long> shopIds) {
        return shopWalletMapper.listByShopIds(shopIds);
    }

    @Override
    public Long getSettlementAmountByShopId(Long shopId) {
        // 这里如果有分片的时候要把分片也一起返回
        ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
        if (Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
            return shopWalletMapper.getSettlementAmountByShopId(shopId);
        } else {
            Long mainSettledAmount = shopWalletMapper.getSettlementAmountByShopId(shopId);
            Long settledAmount = shopWalletZoneMapper.getSettleAmountByShopId(shopId);
            return mainSettledAmount + settledAmount;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rechargeSuccess(RechargeNotifyBO message) {
        Long shopWalletLogId = message.getBalanceLogId();
        MongoShopWalletLogBO shopWalletLogDb = mongoTemplate.findById(shopWalletLogId, MongoShopWalletLogBO.class);
        if (Objects.isNull(shopWalletLogDb)) {
            throw new LuckException("未找到支付成功的钱包日志");
        }
        if (Objects.equals(shopWalletLogDb.getReason(), ShopWalletChangeReason.SUCCESS_RECHARGE.value())) {
            return;
        }

        // 更新店铺余额，充值的余额加至主分片
        Long shopId = shopWalletLogDb.getShopId();
        RLock lock = redissonClient.getLock(LockCacheNames.LOCK_SHOP_WALLET_ZONE_PREFIX + shopId);
        try {
            lock.lock();
            shopWalletMapper.addSettledAmount(shopId, shopWalletLogDb.getShopChangeAmount());
        } finally {
            lock.unlock();
        }

        if (Objects.equals(shopWalletLogDb.getReason(), ShopWalletChangeReason.SUCCESS_QRCODE_RECHARGE.value())) {
            //TODO 如果是收款码支付成功发送模板消息

            // 发送消息给商家，收款码收款成功（即 收款提醒）
            SendNotifyBO notifyBO = new SendNotifyBO();
            notifyBO.setPrice(PriceUtil.toDecimalPrice(shopWalletLogDb.getUserAmount()).toString());
            notifyBO.setShopId(shopWalletLogDb.getShopId());
            notifyBO.setSendType(SendTypeEnum.USER_QRCODE_PAY_SUCCESS.getValue());
            notifyBO.setBizId(shopWalletLogId);
            SendStatus sendShopMsgStatus = updateShopRechargeSuccessTemplate.syncSend(RocketMqConstant.SEND_QRCODE_NOTIFY_TO_SHOP_TOPIC, new GenericMessage<>(notifyBO)).getSendStatus();
            if (!Objects.equals(sendShopMsgStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }


        } else {
            // 更新支付状态
            SendStatus sendWalletLogStatus = updateShopRechargeSuccessTemplate.syncSend(RocketMqConstant.UPDATE_SHOP_RECHARGE_SUCCESS_TOPIC, new GenericMessage<>(message)).getSendStatus();
            if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }

    }

    @Override
    public ShopWalletVO getByShopId(Long shopId) {
        ShopWalletVO shopWallet;
        ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
        if (!Objects.isNull(shopZoneInfo) && Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
            // 如果没有分片就按原来方式获取店铺钱包信息
            shopWallet = shopWalletMapper.getByShopId(shopId);
        } else {
            // 从分片中获取店铺钱包信息
            shopWallet = shopWalletZoneMapper.getShopWalletByZone(shopId);
        }
        return shopWallet;
    }

    @Override
    public ShopWalletVO getAllShop(ShopWalletLogSearchDTO shopWalletLogSearchDTO) {
        ShopWalletVO shopWallet;
        if (Objects.nonNull(shopWalletLogSearchDTO.getStartTime()) && Objects.nonNull(shopWalletLogSearchDTO.getEndTime())) {
            shopWallet = shopWalletLogService.getShopWalletByTime(shopWalletLogSearchDTO);
        } else {
            shopWallet = shopWalletMapper.getAllShop(shopWalletLogSearchDTO);
        }
        return shopWallet;
    }

    @Override
    public PageVO<ShopWalletVO> pageShopWalletByTime(PageDTO pageDTO, ShopWalletLogSearchDTO shopWalletLogSearchDTO) {
        PageVO<ShopWalletVO> shopWalletPage;
        if (Objects.nonNull(shopWalletLogSearchDTO.getStartTime()) && Objects.nonNull(shopWalletLogSearchDTO.getEndTime())) {
            shopWalletPage = shopWalletLogService.pageShopWalletByTime(pageDTO, shopWalletLogSearchDTO);
        } else {
            shopWalletPage = PageUtil.doPage(pageDTO, () -> shopWalletMapper.listAllShopWallet(shopWalletLogSearchDTO));
        }
        return shopWalletPage;
    }

    /**
     * 下单添加待结算金额/分销减少待结算金额
     * 返回分片的序号，之后退款或者分销结算或者订单结算要扣待结算金额时根据分片序号和店铺id来扣减
     * 如果没有分片的话返回null，判断如果是空或就从主分片扣减
     */
    private Integer addUnsettledAmount(Long shopId, Long changeAmount, Integer zoneNo) {
        // 如果是平台的话，直接return就好，因为现在都在mongodb计算金额了
        if(Objects.equals(shopId,Constant.PLATFORM_SHOP_ID)){
            return null;
        }
        ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
        if (Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
            // 未分片就直接按原来的方式增加(因为添加了唯一索引，所以是不用怕多次加钱)
            shopWalletMapper.addUnsettledAmount(shopId, changeAmount);
            return null;
        } else {
            // 通过分片增加待结算金额
            if (Objects.isNull(zoneNo)) {
                Random random = new Random();
                zoneNo = random.nextInt(shopZoneInfo.getZoneNum());
            }
            // 如果是支付增加的待结算金额，这里的待结算金额不会为负
            // 如果是分销进来的这个方法，会根据这笔订单增加的待结算金额的钱包的zoneNo去进行扣减金额，结果也不会是负的
            shopWalletZoneMapper.addUnsettledAmount(shopId, changeAmount, zoneNo);
            return zoneNo;
        }
    }

    /**
     * 退款减少待结算金额
     */
    private boolean subUnsettledAmount(Long shopId, Long orderId, Long changeAmount) {
        ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
        if (Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
            if (Objects.equals(changeAmount, 0L)) {
                // 变化金额为0，不需要更改数据库
                return true;
            }
            // 未分片就直接按原来的方式扣减待结算金额
            return shopWalletMapper.subUnsettledAmount(shopId, changeAmount) > 0;
        } else {
            ShopWalletLogSearchDTO shopWalletLogQuery = new ShopWalletLogSearchDTO();
            shopWalletLogQuery.setOrderId(orderId);
            shopWalletLogQuery.setReason(ShopWalletChangeReason.PAY.value());
            shopWalletLogQuery.setShopId(shopId);
            shopWalletLogQuery.setAmountType(ShopWalletAmountType.UNSETTLED_AMOUNT.value());
            // 找到支付时的钱包日志记录
            MongoShopWalletLogBO shopWalletLog = shopWalletLogService.listByParam(shopWalletLogQuery).get(0);
            if (Objects.isNull(shopWalletLog)) {
                throw new LuckException("未找到支付成功结算的店铺钱包日志");
            }

            Integer zoneNo = shopWalletLog.getZoneNo();
            // 变化金额为0直接返回true，不需要更改数据库
            if (Objects.equals(changeAmount, 0L)) {
                return true;
            }
            if (Objects.isNull(zoneNo)) {
                // 如果是空的，可能是以前的订单数据，从主分片中扣
                return shopWalletMapper.subUnsettledAmount(shopId, changeAmount) > 0;
            }
            return shopWalletZoneMapper.subUnsettledAmount(shopId, changeAmount, zoneNo) > 0;
        }
    }

    /**
     * 代销订单，商家减少结算金额
     */
    @Override
    public boolean subSettledAmount(Long shopId, Long changeAmount) {
        if (Objects.equals(changeAmount, 0L)) {
            return true;
        }

        ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
        if (Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
            // 未分片就直接按原来的方式扣减结算金额
            return shopWalletMapper.subSettledAmount(shopId, changeAmount) > 0;
        } else {
            Random random = new Random();
            int zoneNo = random.nextInt(shopZoneInfo.getZoneNum());

            // 1. 通过次分片扣减
            boolean updateSuccess = shopWalletZoneMapper.subSettledAmount(shopId, changeAmount, zoneNo) > 0;
            if (updateSuccess) {
                return true;
            }

            // 2. 通过次分片扣减失败，因为次分片金额不够，那么尝试从主分片进行扣减，虽然是均分但是有可能商家充值了或者次分片被扣钱了之类的主分片的结算金额比次分片的要多
            boolean mainUpdateSuccess = shopWalletMapper.subSettledAmount(shopId, changeAmount) > 0;
            if (mainUpdateSuccess) {
                return true;
            }

            // 3. 如果主分片也不够扣，再把所有分片统计到主分片进行扣减之后重新分配分片金额
            // 聚合统计结算金额
            Long mainSettleAmount = shopWalletMapper.getSettlementAmountByShopId(shopId);

            Long sumLessZoneSettleAmount = shopWalletZoneMapper.getSettleAmountByShopId(shopId);

            long totalSettleAmount = mainSettleAmount + sumLessZoneSettleAmount;

            if (totalSettleAmount < changeAmount) {
                return false;
            }

            // 剩余的结算金额
            long remainSettleAmount = totalSettleAmount - changeAmount;
            // 把所有的结算金额再次均分
            shopWalletZoneService.updateZoneSettleAmount(shopId, remainSettleAmount, shopZoneInfo.getZoneNum());
            return true;
        }
    }

    @Override
    public List<Map<String,Object>> shop_wallet_by_area(Long areaId,Integer level) {
        List<Map<String,Object>> list=new ArrayList<>();
        //查询永州市下区县
        List<AreaVO> listArea=areaFeignClient.listByPid(areaId).getData();
        for (int i = 0; i < listArea.size(); i++) {
            Map<String,Object> map=new HashMap<>();
            AreaVO areaVO=listArea.get(i);
            //统计每个区县店铺数量
           List<String> listShop= shopDetailService.getShopNameByArea(areaVO.getAreaId(),level);
            map.put("name",areaVO.getAreaName());
            map.put("count",listShop.size());
            Long amount=0L;
            for (int j = 0; j <listShop.size() ; j++) {
                //统计每个区县店铺收入
                ShopWalletLogSearchDTO shopWalletLogSearchDTO=new ShopWalletLogSearchDTO();
                shopWalletLogSearchDTO.setShopName(listShop.get(j));
                amount+=shopWalletMapper.getAllShop(shopWalletLogSearchDTO).getTotalSettledAmount();
            }
            map.put("amount",amount);
            list.add(map);
        }
        return list;
    }

    /**
     * 增加结算金额
     */
    private boolean addSettledAmount(Long shopId, Long changeAmount) {
        if (Objects.equals(changeAmount, 0L)) {
            return true;
        }
        RLock lock = redissonClient.getLock(LockCacheNames.LOCK_SHOP_WALLET_ZONE_PREFIX + shopId);
        try {
            lock.lock();
            ShopWalletZoneInfoVO shopZoneInfo = shopWalletZoneService.getShopZoneInfo(shopId);
            // 变化金额为0，不需要更改数据库
            if (Objects.equals(shopZoneInfo.getZoneNum(), ShopWalletZoneConstant.ZERO)) {
                // 没有分片就按原来的方式增加
                return shopWalletMapper.addSettledAmount(shopId, changeAmount) > 0;
            } else {
                Random random = new Random();
                int zoneNo = random.nextInt(shopZoneInfo.getZoneNum());
                // 通过分片增加
                return shopWalletZoneMapper.addSettledAmount(shopId, changeAmount, zoneNo) > 0;
            }
        } finally {
            lock.unlock();
        }
    }
}
